//TODO: Case where they close app and reopen it.
package com.servertest1;

import java.util.Random;
import android.app.Activity;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TableRow.LayoutParams;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;



public class Board extends Activity{
	private static final int BOARD_HEIGHT = 8;
	private static final int BOARD_WIDTH = 8;
	private static int numMines = 10;

	//Possible spaces
	private static final int BOMB_SPACE = 'B';
	private static final int FLAGGED_SPACE = 'F';

	//Possible outcomes
	private static final int ERROR = -1;
	private static final int BOMB = 0;
	private static final int NUMBER = 1;
	private static final int FLAG = 2;

	// From server
	private String game_board_str;
	private int is_host;
	private int game_id;
	private String board_cover;

	final int GAME_BOARD_INDEX = 0;
	final int YOUR_TURN_INDEX = 1;
	final int HOST_INDEX = 2;
	final int GAME_ID_INDEX = 3;

	final int HOST_PLAYER = 0;
	final int AWAY_PLAYER = 1;
	private final int POINTS_LOST_PER_BOMB = 10;

	Square gameBoard[][];
	private TableLayout mineField;
	private int blockDimension = 50;
	private int blockPadding = 1;
	private SelectedSquare sel;
	private Button uncover;
	private Button diffuse;
	private TextView currentScore;
	private TextView timeRemaining;
	private int score = 0;
	private int pointsLostToBombs = 0;
	
	//There is some error in this number (+2)
	private int secondsRemaining = 122;
	private Handler m_Handler;
	
	private boolean isUncovering = true;
	private boolean isFlagging = false;
	
	private Client client;

	private class SelectedSquare {
		private Square square;
		private boolean selected;
		private int row;
		private int col;

		public SelectedSquare()
		{
			selected = false;
			row = -1;
			col = -1;
		}

		public void highlightSquare() {
			if(isUncovering){
				int status = -1;
				if(!gameBoard[sel.row][sel.col].isCovered() || gameBoard[sel.row][sel.col].isFlagged())
					return;
				status = checkSpot(sel.row, sel.col);

				if(status == BOMB){
					score -= POINTS_LOST_PER_BOMB;
					pointsLostToBombs += POINTS_LOST_PER_BOMB;
					currentScore.setText(Integer.toString(score));
					/*String[] cmd = new String[3];
					cmd[0] = "turn_over";
					cmd[1] = Integer.toString(score);
					cmd[2] = Integer.toString(game_id);
					new Game_Over().execute(cmd);*/
				}
				else if(status == ERROR){
					Toast.makeText(Board.this, "Something went horribly wrong", Toast.LENGTH_LONG).show();
				}
				else if(status == NUMBER) {
					System.out.println((BOARD_HEIGHT * BOARD_WIDTH) - score - numMines - pointsLostToBombs);
					if((BOARD_HEIGHT * BOARD_WIDTH) - score - numMines - pointsLostToBombs <= 0){
						score += secondsRemaining;
						String[] cmd = new String[3];
						cmd[0] = "turn_over";
						cmd[1] = Integer.toString(score);
						cmd[2] = Integer.toString(game_id);
						
						/*DatabaseHelper dh = new DatabaseHelper(Board.this);
						System.out.println(dh.deleteBoardData(game_id));
						dh.close();*/
						
						new Game_Over().execute(cmd);
					}
				}

				// This is the last thing that should be done in onClick.
				for(int i = 0; i < BOARD_HEIGHT; i++){
					for(int j = 0; j < BOARD_WIDTH; j++){
						gameBoard[i][j].showText();
					}
				}
		
			}
			else{
				if(!gameBoard[sel.row][sel.col].isCovered()){
					System.out.print("Returning when shouldn't!");
					return;
				}
					
				int status = flagMine(sel.row, sel.col);
					
				if (status == ERROR)
				{
					System.out.println("The impossible 'if' has happened...");
				}
				else if(status == FLAG){
					gameBoard[sel.row][sel.col].updateFlag();
					gameBoard[sel.row][sel.col].showText();
				}
				else
				{
					System.out.println("The impossible 'else' has happened...#odoylerulz");
				}
			}
		}

		public void unhighlightSquare()
		{
			square = gameBoard[row][col];
		}
	}


	private void reduceTime() {
		this.secondsRemaining--;
		if (this.secondsRemaining <= 0){
			String[] cmd = new String[3];
			cmd[0] = "turn_over";
			cmd[1] = Integer.toString(score);
			cmd[2] = Integer.toString(game_id);
			
			/*DatabaseHelper dh = new DatabaseHelper(Board.this);
			System.out.println(dh.deleteBoardData(game_id));
			dh.close()*/;
			
			new Game_Over().execute(cmd);
		}
		timeRemaining.setText(Integer.toString(this.secondsRemaining));
	}
	
	Runnable updateTime = new Runnable() {
		public void run() {
			reduceTime();
			m_Handler.postDelayed(updateTime, 1000);
		}
	};
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.board);

		Bundle extras = getIntent().getExtras();
		String[] BoardData = extras.getStringArray("board_data");

		// Get user of current phone
		DatabaseHelper dh = new DatabaseHelper(this);
		String your_name = dh.getUser();
		String[] boardDataFromDatabase = dh.getBoardData(Integer.parseInt(BoardData[GAME_ID_INDEX]));
		System.out.println(boardDataFromDatabase[0]);
		if(false){//!boardDataFromDatabase[0].equals("no_result")) {
			System.out.println("Loading data from board!!");
			board_cover = boardDataFromDatabase[1];
			secondsRemaining = Integer.parseInt(boardDataFromDatabase[2]);
			score = Integer.parseInt(boardDataFromDatabase[3]);
		}
		else {
			board_cover = createCoveredBoard();
			score = 0;
		}
		dh.close();

		// Set server variables
		game_board_str = BoardData[GAME_BOARD_INDEX];
		is_host = (your_name.equals(BoardData[HOST_INDEX])) ? 0 : 1;
		game_id = Integer.parseInt(BoardData[GAME_ID_INDEX]);
		currentScore = (TextView) findViewById(R.id.currentScore);
		timeRemaining = (TextView) findViewById(R.id.timeRemaining);
		currentScore.setText(Integer.toString(score));
		timeRemaining.setText(Integer.toString(secondsRemaining));
		m_Handler = new Handler();
		updateTime.run();
		
		// Set board variables
		mineField = (TableLayout)findViewById(R.id.MineField);
		uncover = (Button) findViewById(R.id.uncover);
		uncover.setBackgroundResource(R.drawable.defuse);
		//diffuse = (Button) findViewById(R.id.diffuse);
		
		uncover.setOnClickListener(new OnClickListener() 
		{

			public void onClick(View v) 
			{
				if(isUncovering){
					isUncovering = false;
					isFlagging = true;
					uncover.setBackgroundResource(R.drawable.uncover_real);
				}
				else{
					isFlagging = false;
					isUncovering = true;
					uncover.setBackgroundResource(R.drawable.defuse);
				}
			}
		});

		setupBoard(numMines);
		displayMines();

		sel = new SelectedSquare();
		client = new Client();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		m_Handler.removeCallbacks(updateTime);
		
		/*DatabaseHelper dh = new DatabaseHelper(this);
		dh.insertBoard(game_id, condenseBoard(gameBoard), getCover(gameBoard), secondsRemaining + 1, score);
		dh.close();*/
	}
	
	private static String getCover(Square[][] game_board)
	{
		String board = "";
		
		for (int i = 0; i < BOARD_HEIGHT; i++)
		{
			for (int j = 0; j < BOARD_WIDTH; j++)
			{
				if (game_board[i][j].isCovered())
				{
					board += "C";
				}
				else
				{
					board += "U";
				}
			}
		}
		
		return (board.length() == BOARD_WIDTH * BOARD_HEIGHT) ? board : "Board length incorrect in updateCover...#odoylerulz";
	}
	
	public static String createCoveredBoard(){
		String theBoard = "";
		
		for(int i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; i++){
			theBoard += "C";
		}
		
		return theBoard;
	}
	
	private static String condenseBoard(Square[][] game_board)
	{
		String board = "";
		
		for (int i = 0; i < BOARD_HEIGHT; i++)
		{
			for (int j = 0; j < BOARD_WIDTH; j++)
			{
				if (game_board[i][j].getValue() >= 'A' && game_board[i][j].getValue() <= 'D')
				{
					board += (char) game_board[i][j].getValue();
				}
				else
				{
					board += Integer.toString(game_board[i][j].getValue());
				}
			}
		}
		
		return board;
	}


	public void setupBoard(int numMines){
		gameBoard = new Square[BOARD_HEIGHT][BOARD_WIDTH];

		// Index of game board string
		int square_index = 0;

		// Loop through each square and create a new object
		for(int i = 0; i < BOARD_HEIGHT; i++){
			for(int j = 0; j < BOARD_WIDTH; j++){
				gameBoard[i][j] = new Square(this);

				if(game_board_str.charAt(square_index) >= 'A' && game_board_str.charAt(square_index) <= 'D'){
					gameBoard[i][j].setValue(game_board_str.charAt(square_index));
				}
				else{
					gameBoard[i][j].setValue(game_board_str.charAt(square_index) - '0');
				}
				
				if (board_cover.charAt(square_index) == 'C')
				{
					gameBoard[i][j].setCover(true);
				}
				else
				{
					gameBoard[i][j].setCover(false);
				}
				
				square_index++;

				final int row = i;
				final int col = j;

				// Assign a click listener to every square
				gameBoard[i][j].setOnClickListener(new OnClickListener()
				{
					public void onClick(View v) 
					{
						// If another square is highlighted, unhighlight it
						if (sel.selected)
						{
							sel.unhighlightSquare();

							// Need an event to trigger a change on the button
							gameBoard[sel.row][sel.col].showText();
						}
						else sel.selected = true;

						// Update which square has been selected
						sel.row = row;
						sel.col = col;

						// Highlight newly pressed square
						sel.highlightSquare();
					}
				});
			}
		}
		
		for(int i = 0; i < BOARD_HEIGHT; i++){
			for(int j = 0; j < BOARD_WIDTH; j++){
				gameBoard[i][j].showText();
			}
		}


	}

	public void calculateNumbers(){
		for(int i = 0; i < BOARD_HEIGHT; i++){
			for(int j = 0; j < BOARD_WIDTH; j++){
				if(gameBoard[i][j].getValue() == BOMB)
					continue;
				int numBombs = 0;
				for(int k = -1; k <= 1; k++){
					for(int l = -1; l <= 1; l++){
						if(i + k < BOARD_HEIGHT && i + k >= 0 && j + l >= 0 && j + l < BOARD_WIDTH){
							if(gameBoard[i+k][j+l].getValue() == BOMB)
								numBombs++;
						}						
					}
				}
				gameBoard[i][j].setValue(numBombs);
			}
		}
	}

	public int checkSpot(int row, int col){
		if(!gameBoard[row][col].isCovered())
			return ERROR;
		else if(gameBoard[row][col].getValue() == BOMB_SPACE){
			gameBoard[row][col].setCover(false);
			return BOMB;
		}
		else if(gameBoard[row][col].getValue() == FLAGGED_SPACE){
			return FLAG;
		}
		else if(gameBoard[row][col].getValue() >= 0 && gameBoard[row][col].getValue() <= 8){
			this.score++;
			gameBoard[row][col].setCover(false);
			if(gameBoard[row][col].getValue() == 0){
				this.clearRoundEmpty(row, col);
			}
			currentScore.setText(Integer.toString(score));
			return NUMBER;
		}
		return ERROR;	
	}

	private void clearRoundEmpty(int row, int col){
		for(int k = -1; k <= 1; k++){
			for(int l = -1; l <= 1; l++){
				if(row + k < BOARD_HEIGHT && row + k >= 0 && col + l >= 0 && col + l < BOARD_WIDTH){
					if(gameBoard[row + k][col + l].isCovered()  && gameBoard[row + k][col + l].getValue() == 0){
						this.score++;
						gameBoard[row + k][col + l].setCover(false);
						clearRoundEmpty(row + k, col + l);
					}
					else if(gameBoard[row + k][col + l].isCovered()){
						this.score++;
						gameBoard[row + k][col + l].setCover(false);
					}
				}						
			}
		}
	}

	public int flagMine(int row, int col){
		if(!gameBoard[row][col].isCovered())
			return ERROR;
		else{
			return FLAG;
		}
	}

	private void displayMines(){
		for(int i = 0; i < BOARD_HEIGHT; i++){
			TableRow row = new TableRow(this);
			row.setLayoutParams(
					new LayoutParams((blockDimension) * BOARD_WIDTH, blockDimension));

			for(int j = 0; j < BOARD_WIDTH; j++){
				gameBoard[i][j].setLayoutParams(new LayoutParams(blockDimension, blockDimension));
				//gameBoard[i][j].setPadding(blockPadding, blockPadding, 0, 0);
				row.addView(gameBoard[i][j]);
			}
			mineField.addView(row, new
					TableLayout.LayoutParams((blockDimension) * BOARD_WIDTH, blockDimension));

		}
	}
	
	private class Game_Over extends AsyncTask<String, Void, String[]> {
		protected String[] doInBackground(String... cmd) {
			// Connect to server
			if (client == null) {
				client = new Client();
			}

			client.connect();
			System.out.println("Sending data");
			client.sendData(cmd);
			String[] result = client.recieveData();
			client.close();

			return result;
		}
		
		protected void onPostExecute(String[] result) {
			if(result[0].equals("board_updated")){
				System.out.println("in board updated!");
				Intent goBack = new Intent();
				goBack.putExtra("game_finished", result);
				setResult(RESULT_OK, goBack);
				finish();
			}
			else{
				System.out.print("ERROR - end of game error");
			}
		}
	}
}